package com.zh.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zh.common.BaseResponse;
import com.zh.common.ErrorCode;
import com.zh.common.ResultUtils;
import com.zh.constant.UserConstant;
import com.zh.domain.dto.project.*;
import com.zh.domain.entity.Message;
import com.zh.domain.entity.Project;
import com.zh.domain.entity.ProjectDynamics;
import com.zh.domain.entity.ProjectUser;
import com.zh.domain.vo.project.ProjectDynamicVo;
import com.zh.domain.vo.project.ProjectVo;
import com.zh.domain.vo.task.TaskCountVo;
import com.zh.domain.vo.user.UserInProjectVo;
import com.zh.domain.vo.user.UserVO;
import com.zh.exception.ThrowUtils;
import com.zh.service.MessageService;
import com.zh.service.ProjectService;
import com.zh.service.ProjectUserService;
import com.zh.service.UserService;
import com.zh.service.ProjectDynamicsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Api(tags = "ProjectController", value = "项目控制器")
@RestController
@RequestMapping("/project")
@Slf4j
@SaCheckLogin
public class ProjectController {

    private final UserService userService;
    private final ProjectService projectService;

    private final ProjectUserService projectUserService;

    private final ProjectDynamicsService projectDynamicsService;

    private final MessageService messageService;

    public ProjectController(UserService userService, ProjectService projectService, ProjectUserService projectUserService, ProjectDynamicsService projectDynamicsService, MessageService messageService) {
        this.userService = userService;
        this.projectService = projectService;
        this.projectUserService = projectUserService;
        this.projectDynamicsService = projectDynamicsService;
        this.messageService = messageService;
    }

    @PostMapping("/add")
    @ApiOperation(value = "addProject", notes = "管理员,新增项目")
    @SaCheckRole(value = UserConstant.ADMIN)
    public BaseResponse<Integer> addProject(@RequestBody AddProjectRequest addProjectRequest) {
        ThrowUtils.throwIf(null == addProjectRequest, ErrorCode.PARAMS_ERROR);
        Integer result = projectService.addProject(addProjectRequest);
        return ResultUtils.success(result);
    }

    @PostMapping("/update")
    @ApiOperation(value = "updateProject", notes = "管理员,更新项目")
    @SaCheckRole(value = UserConstant.ADMIN)
    public BaseResponse<Boolean> updateProject(@RequestBody UpdateProjectRequest updateProjectRequest) {
        ThrowUtils.throwIf(null == updateProjectRequest, ErrorCode.PARAMS_ERROR);
        Boolean result = projectService.updateProject(updateProjectRequest);
        return ResultUtils.success(result);
    }

    @PostMapping("/page")
    @ApiOperation(value = "pageProject", notes = "分页查询项目")
    public BaseResponse<Page<ProjectVo>> pageProject(@RequestBody PageProjectRequest pageProjectRequest) {
        ThrowUtils.throwIf(null == pageProjectRequest, ErrorCode.PARAMS_ERROR);
        Page<ProjectVo> result = projectService.pageProject(pageProjectRequest);
        return ResultUtils.success(result);
    }

    @GetMapping("/list")
    @ApiOperation(value = "listProject", notes = "查询本团队我参与的项目基本信息")
    public BaseResponse<List<ProjectVo>> listProject(Integer teamId) {
        ThrowUtils.throwIf(null == teamId, ErrorCode.PARAMS_ERROR);
        int loginId = StpUtil.getLoginIdAsInt();
        List<ProjectVo> result = projectService.listMyTeamProject(teamId, loginId);
        return ResultUtils.success(result);
    }


    @DeleteMapping("delete")
    @ApiOperation(value = "deleteProject", notes = "管理员,删除项目")
    @SaCheckRole(value = UserConstant.ADMIN)
    public BaseResponse<Boolean> deleteProject(@RequestParam Integer id) {
        ThrowUtils.throwIf(null == id, ErrorCode.PARAMS_ERROR);
        Boolean result = projectService.removeById(id);
        return ResultUtils.success(result);
    }

    @GetMapping("/members")
    @ApiOperation(value = "getMembers", notes = "获取项目成员")
    public BaseResponse<List<UserInProjectVo>> getMembers(Integer id) {
        //1.参数校验
        ThrowUtils.throwIf(null == id, ErrorCode.PARAMS_ERROR);
        //2.查询项目
        Project project = projectService.getById(id);
        ThrowUtils.throwIf(null == project, ErrorCode.PARAMS_ERROR, "项目不存在");
        //3.查询项目成员
        LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectUser::getProId, id);
        List<ProjectUser> list = projectUserService.list(queryWrapper);
        if (list.isEmpty()) {
            return ResultUtils.success(new ArrayList<>());
        }
        List<UserInProjectVo> resultList = list.stream().map(projectUser -> BeanUtil.copyProperties(projectUser, UserInProjectVo.class)).collect(Collectors.toList());
        List<Integer> userIds = list.stream().map(ProjectUser::getUserId).collect(Collectors.toList());
        //4.查询用户信息
        List<UserVO> userVOList = userService.listUserVoByIds(userIds);
        Map<Integer, UserVO> userVOMap = userVOList.stream().collect(Collectors.toMap(UserVO::getId, userVO -> userVO));
        resultList.forEach(userInProjectVo -> {
            UserVO userVO = userVOMap.get(userInProjectVo.getUserId());
            BeanUtil.copyProperties(userVO, userInProjectVo);
        });
        return ResultUtils.success(resultList);
    }

    @PostMapping("/addMembers")
    @ApiOperation(value = "addMembers", notes = "添加项目成员")
    @Transactional
    public BaseResponse<Boolean> addMembers(@RequestBody AddMembersRequest addMembersRequest) {
        //1.参数校验
        ThrowUtils.throwIf(null == addMembersRequest, ErrorCode.PARAMS_ERROR);
        boolean res = projectService.addMembers(addMembersRequest);
        return ResultUtils.success(res);
    }

    @PostMapping("/removeMembers")
    @ApiOperation(value = "removeMembers", notes = "移除项目成员")
    public BaseResponse<Boolean> removeMembers(@RequestBody RemoveMembersRequest removeMembersRequest) {
        //1.参数校验
        ThrowUtils.throwIf(null == removeMembersRequest, ErrorCode.PARAMS_ERROR);
        boolean result = projectService.removeUserByProIdAndUserIdList(removeMembersRequest);
        return ResultUtils.success(result);
    }

    @GetMapping("/isProjectMember")
    @ApiOperation(value = "isMember", notes = "判断用户是否是项目成员")
    public BaseResponse<Boolean> isProjectMember(Integer proId) {
        ThrowUtils.throwIf(null == proId, ErrorCode.PARAMS_ERROR);
        int loginIdAsInt = StpUtil.getLoginIdAsInt();
        LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectUser::getProId, proId)
                .eq(ProjectUser::getUserId, loginIdAsInt);
        ProjectUser one = projectUserService.getOne(queryWrapper);
        return ResultUtils.success(null != one);
    }

    @PostMapping("/update/member")
    @ApiOperation(value = "updateUserInProject", notes = "修改项目成员角色")
    @Transactional
    public BaseResponse<Boolean> updateUserInProject(@RequestBody UpdateUserInProjectRequest updateUserInProjectRequest) {
        // 1. 参数校验
        ThrowUtils.throwIf(null == updateUserInProjectRequest, ErrorCode.PARAMS_ERROR);
        Integer role = updateUserInProjectRequest.getRole();
        Integer proId = updateUserInProjectRequest.getProId();
        Integer userId = updateUserInProjectRequest.getUserId();
        String tag = updateUserInProjectRequest.getTag();
        ThrowUtils.throwIf(null == proId || null == userId, ErrorCode.PARAMS_ERROR);
        // 2. 修改项目成员角色 标签 至少有一个不为空
        if (role == null && StrUtil.isEmpty(tag)) {
            return ResultUtils.success(false);
        }
        LambdaUpdateWrapper<ProjectUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProjectUser::getProId, proId)
                .eq(ProjectUser::getUserId, userId)
                .set(role != null, ProjectUser::getRole, role)
                .set(StrUtil.isNotEmpty(tag), ProjectUser::getTag, tag);
        boolean result = projectUserService.update(updateWrapper);

        // 3. 插入动态 发送通知
        if (result) {
            int loginId = StpUtil.getLoginIdAsInt();
            List<UserVO> userVOS = userService.listUserVoByIds(Arrays.asList(loginId, userId));

            // 找到发送方和接收方
            UserVO sendUser = userVOS.stream()
                    .filter(userVO -> userVO.getId().equals(loginId))
                    .findFirst()
                    .orElseGet(UserVO::new);
            UserVO receiveUser = userVOS.stream()
                    .filter(userVO -> userVO.getId().equals(userId))
                    .findFirst()
                    .orElseGet(UserVO::new);

            // 异步插入动态
            CompletableFuture.runAsync(() -> {

                String content = "";
                if (role != null) {
                    content = sendUser.getName() + "将 " + receiveUser.getName() + "设置为 " + (role == 1 ? "管理员" : "普通成员") + ".";
                }
                if (StrUtil.isNotEmpty(tag)) {
                    content = sendUser.getName() + "将 " + receiveUser.getName() + "设置为 " + tag + ".";
                }
                ProjectDynamics dynamics = new ProjectDynamics();
                dynamics.setContent(content);
                dynamics.setCreateAt(LocalDateTime.now());
                dynamics.setCreateBy(loginId);
                dynamics.setUpdateAt(LocalDateTime.now());
                dynamics.setUpdateBy(loginId);
                dynamics.setProId(proId);
                dynamics.setStatus(1);
                dynamics.setDeleted(0);
                projectDynamicsService.save(dynamics);
            }).exceptionally(ex -> {
                log.error("插入项目动态失败", ex);
                return null;
            });

            // 异步发送通知
            CompletableFuture.runAsync(() -> {
                Message message = new Message();
                String content = "";
                if (role != null) {
                    content = sendUser.getName() + "将你设置为 " + (role == 1 ? "管理员" : "普通成员") + ".";
                }
                if (StrUtil.isNotEmpty(tag)) {
                    content = sendUser.getName() + "将你" + "设置为" + tag + "。";
                }
                message.setContent(content);
                message.setCreateAt(LocalDateTime.now());
                message.setCreateBy(loginId);
                message.setUpdateAt(LocalDateTime.now());
                message.setUpdateBy(loginId);
                message.setNoticeType(0);
                message.setType(1);
                message.setParams(Map.of(
                        "proId", proId.toString(),
                        "payloadType", "project",
                        "title", projectService.getById(proId).getTitle()
                ));
                message.setStatus(1);
                messageService.sendMessage(message, List.of(userId));
            }).exceptionally(ex -> {
                log.error("发送通知失败 " + ex);
                return null;
            });
        }

        return ResultUtils.success(result);
    }

    @PostMapping("/dynamic/page")
    @ApiOperation(value = "pageProjectDynamic", notes = "获取项目动态")
    public BaseResponse<Page<ProjectDynamicVo>> pageProjectDynamic(@RequestBody PageProjectDynamicRequest pageRequest) {
        //1.参数校验
        ThrowUtils.throwIf(null == pageRequest, ErrorCode.PARAMS_ERROR);
        Integer proId = pageRequest.getProId();
        Integer userId = pageRequest.getUserId();
        String searchText = pageRequest.getSearchText();
        pageRequest.standardizeSize();
        //2.查询动态(按时间倒序)
        Integer current = pageRequest.getCurrent();
        Integer pageSize = pageRequest.getPageSize();
        Page<ProjectDynamics> page = new Page<>(current, pageSize);
        LambdaQueryWrapper<ProjectDynamics> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectDynamics::getProId, proId)
                .eq(ProjectDynamics::getDeleted, 0)
                .eq(ProjectDynamics::getStatus, 1)
                .eq(null != userId, ProjectDynamics::getCreateBy, userId)
                .like(null != searchText, ProjectDynamics::getContent, searchText)
                .orderByDesc(ProjectDynamics::getCreateAt)
                .orderByDesc(ProjectDynamics::getUpdateAt)
                .orderByDesc(ProjectDynamics::getId);
        Page<ProjectDynamics> projectDynamicsPage = projectDynamicsService.page(page, queryWrapper);
        List<ProjectDynamics> records = projectDynamicsPage.getRecords();
        //3.查询用户信息
        List<Integer> userIds = records.stream().map(ProjectDynamics::getCreateBy).collect(Collectors.toList());
        List<UserVO> userVOList = userService.listUserVoByIds(userIds);
        Map<Integer, UserVO> userVOMap = userVOList.stream().collect(Collectors.toMap(UserVO::getId, userVO -> userVO));
        //4.封装数据
        List<ProjectDynamicVo> result = records.stream().map(projectDynamics -> {
            ProjectDynamicVo projectDynamicVo = new ProjectDynamicVo();
            BeanUtil.copyProperties(projectDynamics, projectDynamicVo);
            UserVO userVO = userVOMap.get(projectDynamics.getCreateBy());
            projectDynamicVo.setOperator(userVO);
            return projectDynamicVo;
        }).collect(Collectors.toList());
        Page<ProjectDynamicVo> pageResult = new Page<>(current, pageSize);
        BeanUtil.copyProperties(projectDynamicsPage, pageResult);
        pageResult.setRecords(result);
        return ResultUtils.success(pageResult);
    }

    @GetMapping
    @ApiOperation(value = ("getProject"), notes = "根据id获取项目信息")
    public BaseResponse<ProjectVo> getProject(Integer id) {
        ThrowUtils.throwIf(null == id, ErrorCode.PARAMS_ERROR);
        ProjectVo projectVo = projectService.getProject(id);
        return ResultUtils.success(projectVo);
    }
    @GetMapping("/taskCount")
    @ApiOperation(value = "getTaskCount", notes = "获取项目任务统计信息")
    public BaseResponse<TaskCountVo> getTaskCountByProId(Integer proId) {
        TaskCountVo taskCountVo = projectService.getTaskCount(proId);
        return ResultUtils.success(taskCountVo);
    }
}
